package shell

import (
	"bufio"
	"fmt"
	"io"
	"sort"
	// "io/ioutil"
	// "os/exec"
	// "sdk/sdklog"
	"log"
	"os"
	"sdk/utils"
	"strings"
)

const (
	SHOW     = "show"
	EXIT     = "exit"
	QUIT     = "quit"
	QUESTION = "?"
	HELP     = "help"
)

var (
	g_shell *Shell = New()
)

type cmd_func func(v ...interface{}) bool

type shell_cmd struct {
	name    string
	proc    cmd_func
	sub_cmd map[string]*shell_cmd
}

type Shell struct {
	shell_cmd *shell_cmd
	stack     *utils.Stack
}

func New() *Shell {
	s := &Shell{}

	s.shell_cmd = getNewCmd("", nil)
	//退出命令
	s.shell_cmd.registerCmd(QUIT, nil)
	s.shell_cmd.registerCmd(SHOW, nil)
	s.stack = utils.NewStack()

	return s
}

func RegisterElement(name string) {
	g_shell.RegisterElement(name)
}

func (s *Shell) RegisterElement(name string) {
	s.shell_cmd.registerElement(name)
}

func getNewCmd(name string, proc cmd_func) *shell_cmd {
	return &shell_cmd{name, proc, make(map[string]*shell_cmd)}
}

//注册个命令节点
func (cmd *shell_cmd) registerElement(name string) *shell_cmd {
	a := getNewCmd(name, nil)

	a.registerCmd(SHOW, nil)
	a.registerCmd(EXIT, nil)
	a.registerCmd(QUIT, nil)

	cmd.sub_cmd[name] = a

	return cmd.sub_cmd[name]
}

func RegisterCmd(parent_name string, name string, proc cmd_func) {
	g_shell.RegisterCmd(parent_name, name, proc)
}

func (s *Shell) RegisterCmd(parent_name string, name string, proc cmd_func) {
	parent, ok := s.shell_cmd.sub_cmd[parent_name]
	if !ok {
		fmt.Println("parent_name=", parent_name, "is not found")
		return
	}

	parent.registerCmd(name, proc)
}

//注册个命令
func (cmd *shell_cmd) registerCmd(name string, proc cmd_func) {
	a := getNewCmd(name, proc)

	cmd.sub_cmd[name] = a
}

func (cmd *shell_cmd) printSubCmd() {
	i := 0
	tmp := []string{}
	for _, cmd := range cmd.sub_cmd {
		tmp = append(tmp, cmd.name)
	}
	sort.Strings(tmp)
	for _, name := range tmp {
		fmt.Printf("%s ", name)
		i = i + 1
		if i%5 == 0 {
			fmt.Println("")
		}
	}
	fmt.Println("")
}

func Run(r io.Reader) {
	g_shell.Run(r)
}

func (s *Shell) Run(r io.Reader) {
	reader := bufio.NewReader(r)
	fmt.Println("welcome to consol shell")
	for {
		fmt.Printf("shell")
		top := s.stack.Peak()
		if top != nil {
			fmt.Printf(" %s", top.(*shell_cmd).name)
		}
		fmt.Printf("->")
		str, err := reader.ReadString('\n')
		if err != nil {
			log.Panic("failed to ReadString ", err)
		}
		str = strings.Trim(str, "\r\n")
		str = strings.TrimSpace(str)
		if str == "" {
			continue
		}
		//拆分命令行
		sa := strings.Split(str, " ")
		//清除下空格
		i := 0
		for i = 0; i < len(sa); i++ {
			sa[i] = strings.TrimSpace(sa[i])
		}
		s.goCmdProc(sa)
	}
}

func (s *Shell) goCmdProc(sa []string) {
	if len(sa) == 0 {
		return
	}
	//取得当前命令节点
	cur_element := s.shell_cmd
	e := s.stack.Peak()
	if e != nil {
		cur_element = e.(*shell_cmd)
	}
	if sa[0] == QUESTION ||
		sa[0] == HELP ||
		sa[0] == SHOW {
		//帮助
		cur_element.printSubCmd()
		return
	}
	if sa[0] == EXIT {
		//退出当前级
		s.goExitProc()
		return
	}
	if sa[0] == QUIT {
		//关闭
		s.goQuitProc()
		return
	}

	for _, sub := range cur_element.sub_cmd {
		if sub.name == sa[0] {
			if sub.proc == nil {
				//进入命令节点
				s.goEnterProc(sub)
				return
			}
			//第一个参数为parent,第二个参数为自己命令节点，第三个是参数字符串切片
			if !sub.proc(cur_element, sub, sa[1:]) {
				cur_element.printSubCmd()
			}
			return
		}
	}

	cur_element.printSubCmd()
}

func (s *Shell) goQuitProc(v ...interface{}) bool {
	fmt.Println("bye bye!!!!")
	os.Exit(0)

	return true
}

func goShowProc(v ...interface{}) bool {
	cmd := v[0].(*shell_cmd)
	cmd.printSubCmd()

	return true
}

func (s *Shell) goEnterProc(v ...interface{}) bool {
	//判断下合法性
	// fmt.Println("goto enter proc len=", len(v))
	if len(v) == 0 {
		return false
	}
	d := v[0].(*shell_cmd)
	if d.proc != nil {
		fmt.Println("%s proc need nil", d.name)
		return false
	}

	s.stack.Push(d)

	return true
}

func (s *Shell) goExitProc(v ...interface{}) bool {
	if !s.stack.Empty() {
		s.stack.Pop()
	}
	return true
}
